package com.lesso.curry.reflect;

import com.lesso.curry.SapField;
import com.lesso.curry.util.ReflectUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 映射实体类
 *
 * @author zqz
 * @since 2022-12-01
 */
public final class SapReflect {
    private SapReflect() {
    }

    private static final ConcurrentHashMap<Class<?>, Map<String, ReflectProperties>> CACHE = new ConcurrentHashMap<>();

    public static Map<String, ReflectProperties> mapping(Class<?> clazz) {
        Map<String, ReflectProperties> map = CACHE.get(clazz);
        if (map != null) {
            return map;
        }
        map = new HashMap<>();
        List<Field> fields = ReflectUtils.getAllFields(clazz);
        for (Field field : fields) {
            SapField sapField = field.getAnnotation(SapField.class);
            if (sapField == null) {
                continue;
            }
            map.put(field.getName(), new ReflectProperties(setter(clazz, field, sapField), getter(clazz, field, sapField), sapField));
        }
        CACHE.put(clazz, map);
        return map;
    }

    private static Method setter(Class<?> clazz, Field field, SapField sapField) {
        String setterName = setterName(field.getName(), sapField.setter());
        return ReflectUtils.findMethod(setterName, clazz, field.getType());
    }

    private static Method getter(Class<?> clazz, Field field, SapField sapField) {
        String getterName = getterName(field.getName(), sapField.getter());
        return ReflectUtils.findMethod(getterName, clazz);
    }

    private static String getterName(String fieldName, String getter) {
        return methodName(fieldName, getter, "get");
    }

    private static String setterName(String fieldName, String setter) {
        return methodName(fieldName, setter, "set");
    }

    private static String methodName(String fieldName, String methodName, String prefix) {
        if (methodName != null && !Objects.equals(methodName.trim(), "")) {
            return methodName;
        }
        char[] chars = fieldName.toCharArray();
        chars[0] = Character.toUpperCase(chars[0]);
        return prefix + new String(chars);
    }

}
